home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1995 November / EnigmA AMIGA RUN 02 (1995)(G.R. Edizioni)(IT)[!][issue 1995-11][Skylink CD].iso / earcd / gfx / jpegaga2.lha / jpegAGAsrc / ppm2aga / ppm2ilbm.c < prev    next >
C/C++ Source or Header  |  1995-04-08  |  31KB  |  999 lines

  1. /* ppm2ilbm module                 */
  2. /* written by Günther Röhrich      */
  3. /* this is version 1.5             */
  4.  
  5. /* this code is tested with Aztec C 5.2a and GNU C 2.5.8 */
  6. /* NOTE: you will need the newiff V37 or higher package */
  7. /* (V37 is available on Fish-disk 705) */
  8.  
  9.  
  10. #include <clib/exec_protos.h>
  11. #include <libraries/iffparse.h>
  12. #include <dos/dos.h>
  13. #include <iffp/ilbmapp.h>
  14. #include <iffp/packer.h>
  15. #include <stdio.h>
  16. #include <graphics/modeid.h>
  17.  
  18. #include "ppm2AGA.h"
  19.  
  20. #ifndef __GNUC__
  21. #include <pragmas/exec_pragmas.h>
  22. #include <pragmas/iffparse_pragmas.h>
  23. #endif
  24.  
  25.  
  26.  
  27. /* needed when compiling with newiff V37 package */
  28. /* (not needed with V39 or higher) */
  29.  
  30. #ifndef BMHDF_CMAPOK
  31. #define BMHDF_CMAPOK (1 << 7)
  32. #endif
  33.  
  34. #define random rand
  35.  
  36. /* externals used by this module */
  37.  
  38.  
  39. extern int AbortCheck(void);
  40. extern void PLProgress(ULONG Value, ULONG MaxValue);
  41. extern volatile unsigned short MaxError, MaxErrorPos;
  42. extern void EncodeHAM(UBYTE *yorig, UBYTE *yham, char *ColorTable, 
  43.                        short NumColors, short xsize);
  44. extern int MapColorASM(colorhist_vector colormap, pixval r1, pixval g1, pixval b1, 
  45.              int NumColors);
  46. extern int ExactColor;
  47. extern int GfxEnable;
  48. extern int VGAenable;
  49. extern int jpegAGA;
  50. extern char *ILBMfile;
  51. extern char *BaseName;
  52. extern ULONG SMR;
  53. extern ULONG SMR_DisplayID;
  54.  
  55. /* definitions for the display routines */
  56.  
  57. extern int InitDisplay(int cols, int rows, ULONG Mode, int NumPlanes);
  58. extern void SetDisplayColor(int ColorNumber, UBYTE r, UBYTE g, UBYTE b);
  59. extern void DisplayRow(char *array, int cols, int row);
  60. extern void CloseDisplay(void);
  61.  
  62. /* globals defined in this module */
  63.  
  64. #ifdef DEBUG_ASM
  65. int MapColor(colorhist_vector colormap, pixval r1, pixval g1, pixval b1, 
  66.              int NumColors);
  67. #endif
  68.  
  69. unsigned short Mult_Table[2*256];
  70. unsigned long  Mult_Table32[2*256];
  71. jmp_buf ErrorEnv;
  72. int cols, rows, rowcnt;
  73. pixel **pixels;
  74. pixel *pixrow;
  75. pixval maxval;
  76. int ppmformat;
  77. char ColorTable[64*3] = {0};
  78. int ColorRegMax; 
  79. unsigned short ConvertMode;
  80. char *ColorCache; /* a 256K cache for EncodeHAM() */
  81.  
  82. /* these are needed by Floyd-Steinberg-routines */
  83. long  *thisrerr;
  84. long  *nextrerr;
  85. long  *thisgerr;
  86. long  *nextgerr;
  87. long  *thisberr; 
  88. long  *nextberr;     
  89. extern int floyd; 
  90. int fs_direction = 1;
  91. int Convert4096;
  92. int Convert262144;
  93. #define FS_SCALE 1024
  94.  
  95. /* locals defined in this module */
  96.  
  97. static FILE *fppm;
  98. static FILE *ColorMapFile;
  99. static struct IFFHandle *iff;
  100. static struct ILBMInfo ilbm;
  101. static int error;
  102. static LONG IFFError;
  103. static unsigned char *coded_rowbuf;
  104. static unsigned char *hamarray;
  105. static int returnvalue;
  106. static void ppmCleanUp(void);
  107. static int readall;
  108. static colorhist_vector chv, colormap;
  109. static BYTE *CompressBuffer;
  110. static void encode_row(UBYTE *row, int cols, int nPlanes);
  111. static int ColorShift, NumColors;
  112. static gray *pgmrow;
  113.  
  114. static int lumcompare(colorhist_vector ch1, colorhist_vector ch2)
  115. {
  116.  return (int)((double)PPM_LUMIN(ch1->color) - (double)PPM_LUMIN(ch2->color));
  117. }
  118.  
  119.  
  120. int ppm2ilbm(char *PPMfile, ULONG Mode, int NumPlanes, ULONG MaxMem)
  121. {
  122.  int i, colors;
  123.  pixel *pP;
  124.  unsigned short AbsMaxError = 0;
  125.  unsigned short MaxErrorXPos = 0;
  126.  unsigned short MaxErrorYPos = 0;
  127.  
  128.  /* initialize everything                            */
  129.  /* this is needed because we may call this function */
  130.  /* multiple times                                   */
  131.  returnvalue = 0;
  132.  fppm = NULL;
  133.  ColorMapFile = NULL;
  134.  readall = 0;
  135.  pixrow = NULL;
  136.  pixels = NULL;
  137.  hamarray = NULL; coded_rowbuf = NULL; ColorCache=NULL; 
  138.  memset(&ilbm, 0, sizeof(struct ILBMInfo)); 
  139.  chv = NULL;
  140.  colormap = NULL;
  141.  CompressBuffer = NULL;
  142.  pgmrow = NULL;
  143.  
  144.  
  145.  /* multiplication table is needed by assembler subroutines */
  146.  for(i=-255; i<256; i++)
  147.  {
  148.    Mult_Table[i+255] = i*i;
  149.    Mult_Table32[i+255] = i*i;
  150.  }
  151.  
  152.  
  153.  /* if we encounter an error we longjmp() to this location       */
  154.  /* the ppmCleanUp() function will free all resources  allocated */
  155.  /* in this module                                               */
  156.  
  157.  error = setjmp(ErrorEnv);
  158.  if(error != 0) 
  159.  {
  160.   ppmCleanUp();
  161.   return error;
  162.  }  
  163.  
  164.  
  165.  /* try to open the ppm file */
  166.  fppm = fopen(PPMfile, "r");
  167.  if(!fppm) pm_error("Could not open file %s\n", PPMfile);
  168.  
  169.  /* read the header of the ppm file */
  170.  ppm_readppminit(fppm, &cols, &rows, &maxval, &ppmformat); 
  171.  
  172.  #ifdef DEBUG
  173.  pm_message("Cols: %d, Rows: %d, MaxVal: %d, Format: %d\n",
  174.              cols, rows, maxval, ppmformat);
  175.  #else
  176.  pm_message("Cols: %d, Rows: %d, MaxVal: %d\n", cols, rows, maxval);
  177.  #endif
  178.  
  179.  /* Initialize Floyd-Steinberg error vectors. */
  180.  thisrerr = (long*) pm_allocrow( cols + 2, sizeof(long) );
  181.  nextrerr = (long*) pm_allocrow( cols + 2, sizeof(long) );
  182.  thisgerr = (long*) pm_allocrow( cols + 2, sizeof(long) );
  183.  nextgerr = (long*) pm_allocrow( cols + 2, sizeof(long) );
  184.  thisberr = (long*) pm_allocrow( cols + 2, sizeof(long) );
  185.  nextberr = (long*) pm_allocrow( cols + 2, sizeof(long) );
  186.  /* srandom( (int) ( time( 0 ) ^ getpid(0) ) ); */
  187.  for ( i = 0; i < cols + 2; ++i )
  188.  {
  189.    thisrerr[i] = random( ) % ( FS_SCALE * 2 ) - FS_SCALE;
  190.    thisgerr[i] = random( ) % ( FS_SCALE * 2 ) - FS_SCALE;
  191.    thisberr[i] = random( ) % ( FS_SCALE * 2 ) - FS_SCALE;
  192.    /* (random errors in [-1 .. 1]) */ 
  193.  }
  194.  
  195.  /* try to open the output file */
  196.  
  197.  if(!jpegAGA)
  198.  {
  199.    if(!(ilbm.ParseInfo.iff = AllocIFF()))
  200.      pm_error("Could not do AllocIFF()");
  201.  
  202.    iff = ilbm.ParseInfo.iff;
  203.  
  204.    IFFError = openifile((struct ParseInfo *)&ilbm, (UBYTE *)ILBMfile, IFFF_WRITE);
  205.    if(IFFError) pm_error(""); /* openifile() will print error messages... */
  206.  }
  207.  
  208.  if(Mode == HAM8 || Mode == HAM6 || Mode == COLORMAP)
  209.  {
  210.    int Clustering;
  211.    if(Mode == HAM8)
  212.    {
  213.      NumColors = NumPlanes;
  214.      ColorRegMax  = 63;
  215.      ColorShift   = 2; /* we only have 256K colors */
  216.      NumPlanes    = 8;
  217.      ConvertMode  = 1; /* Needed by EncodeHAM() */
  218.      Clustering   = 0;
  219.      Convert4096  = 0; /* No 4096-FS conversion */
  220.      if(floyd) Convert262144 = 1; /* 262144 conversion */
  221.     
  222.    }
  223.    else if(Mode == HAM6)
  224.    {
  225.      NumColors = NumPlanes;
  226.      ColorRegMax = 15; 
  227.      ColorShift  = 4; /* converting to 4096 colors will be done by FS dithering */
  228.      NumPlanes   = 6;
  229.      ConvertMode = 0; /* Needed by EncodeHAM() */
  230.      Clustering  = 0;
  231.      if(floyd)
  232.        Convert4096 = 1; /* Do 4096-FS conversion */
  233.      Convert262144 = 0;
  234.    }
  235.    else /* COLORMAP */
  236.    { 
  237.      NumColors = 1 << NumPlanes;      
  238.      ColorRegMax = 255;
  239.      ColorShift = 0; /* we will handle full 16M colors */
  240.      if(ppmformat == PGM_FORMAT || ppmformat == RPGM_FORMAT || ExactColor == 1)
  241.      {
  242.        Clustering = 0;
  243.      }
  244.      else
  245.      {
  246.        Clustering = 2;
  247.      }
  248.      Convert4096 = 0; /* No 4096-FS conversion */
  249.      Convert262144 = 0;
  250.    } 
  251.        
  252.    if( cols*rows*3 <= (int)MaxMem)
  253.    {     
  254.      /* read the complete picture into memory */
  255.      int row;
  256.      readall = 1;
  257.      pm_message("Reading complete picture into memory...\n");
  258.      pixels = ppm_allocarray(cols, rows);     
  259.      for(row = 0; row < rows; ++row)
  260.      {
  261.        if(AbortCheck()) pm_error("^C\n");
  262.        ppm_readppmrow(fppm, pixels[row], cols, maxval, ppmformat);
  263.        if(maxval != ColorRegMax)
  264.        {
  265.          if(maxval == 255)
  266.          {
  267.            for(i=0, pP=pixels[row]; i < cols; ++i, ++pP)
  268.            {
  269.              pP->r = pP->r >> ColorShift;
  270.              pP->g = pP->g >> ColorShift;
  271.              pP->b = pP->b >> ColorShift;
  272.            }
  273.          }
  274.          else
  275.          {
  276.            for(i=0, pP=pixels[row]; i < cols; ++i, ++pP)
  277.              PPM_DEPTH(*pP, *pP, maxval, ColorRegMax);
  278.          }
  279.        }
  280.      }
  281.    }
  282.    else
  283.    {
  284.      rowcnt = 0;
  285.      if(!(pixrow = ppm_allocrow(cols)))
  286.        pm_error("Out of memory.\n");     
  287.     }
  288.  
  289.  
  290.    /* allocate enough room for one row of chunky HAM pixels  */
  291.    /* (this array will also be used for colormap conversion) */
  292.    if(!(hamarray = malloc(RowBits(cols))))
  293.      pm_error("Out of memory.\n");
  294.  
  295.    /* we only have to clear the space between cols and RowBits(cols)    */
  296.    /* hamarray will be larger in most cases because of special alignment*/
  297.    for(i = cols; i < RowBits(cols); i++) hamarray[i] = 0;
  298.    pm_message("Computing colormap...\n");
  299.  
  300.  
  301.    /* now we make a histogram of the picture...          */
  302.    /* if we increase Clustering we will find less colors */
  303.    /* we allow a maximum of 10000 colors                 */
  304.    /* ColorShift is the shift needed for HAM encoding    */
  305.    for(i=Clustering; i<5; i++)
  306.    {
  307.      if((chv = ppm_fcomputecolorhist(fppm, cols, rows, 10000, &colors, ColorShift, i)))
  308.        break;
  309.      if(AbortCheck()) pm_error("^C\n");
  310.      pm_message("Could not compute colormap, trying again...\n");
  311.      rowcnt=0;
  312.      if(!readall)
  313.      { 
  314.        rewind(fppm); /* re-initialise the ppm pointers for reading again */
  315.        ppm_readppminit(fppm, &cols, &rows, &maxval, &ppmformat);       
  316.      }
  317.    } 
  318.  
  319.    pm_message("Found %d colors.\n", colors);
  320.  
  321.  
  322.    /* now we try to find a suitable colormap... */
  323.    colormap = mediancut(chv, colors, rows*cols, ColorRegMax, NumColors);
  324.    ppm_freecolorhist(chv); /* we don't need the histogram any more */
  325.    chv = NULL;
  326.    /* sort the colors in ascending luminance order...  */ 
  327.    /* (the first color will be the background color)      */
  328.    if(NumColors < colors)
  329.    {
  330.      qsort((char *)colormap, NumColors, sizeof(struct colorhist_item), lumcompare);
  331.    }
  332.    else
  333.    {
  334.      qsort((char *)colormap, colors, sizeof(struct colorhist_item), lumcompare);
  335.    }
  336.  
  337.    
  338.    if(!jpegAGA)
  339.    {   
  340.      /* the CompressBuffer is needed by the cmpByteRun1 compressor */
  341.      if(!(CompressBuffer = malloc(MaxPackedSize(RowBytes(cols)))))
  342.        pm_error("Out of memory allocating the compress buffer.\n");
  343.  
  344.      /* the ColorCache is needed by EncodeHAM() for higher speed */
  345.      /* (for HAM6 encoding only 4097 bytes are needed...)        */
  346.      if(!(ColorCache = malloc(262145)))
  347.        pm_error("Out of memory allocating the color cache.\n");
  348.  
  349.      /* the coded_rowbuf is needed by the IFF encoder */
  350.      if(!(coded_rowbuf = (unsigned char *)malloc(RowBytes(cols))))
  351.        pm_error("Out of memory allocating coded_rowbuf.\n");
  352.      for(i=RowBytes(cols)-1; i>=0; i--) coded_rowbuf[i]=0;
  353.  
  354.      /* write the FORM chunk */
  355.      IFFError = PushChunk(iff, ID_ILBM, ID_FORM, IFFSIZE_UNKNOWN);
  356.      if(IFFError) pm_error("Error writing FORM chunk.\n");
  357.      
  358.      /* initialize the BMHD chunk */
  359.      ilbm.Bmhd.w = cols;
  360.      ilbm.Bmhd.h = rows;             /* Width, height in pixels */
  361.      ilbm.Bmhd.x = 0;
  362.      ilbm.Bmhd.y = 0;                /* x, y position for this bitmap  */
  363.      ilbm.Bmhd.nPlanes = NumPlanes;  /* # of planes (not including mask) */
  364.      ilbm.Bmhd.masking = mskNone;   
  365.      ilbm.Bmhd.compression = cmpByteRun1;   
  366.      ilbm.Bmhd.flags = BMHDF_CMAPOK;  /* CMAP has 8 significant bits */
  367.      ilbm.Bmhd.transparentColor = 0; 
  368.      ilbm.Bmhd.xAspect = cols;         
  369.      ilbm.Bmhd.yAspect = rows;       /* xAspect, yAspect */
  370.      ilbm.Bmhd.pageWidth = cols;
  371.      ilbm.Bmhd.pageHeight = rows;    /* pageWidth, pageHeight */
  372.   
  373.      /* write the BMHD chunk */   
  374.      IFFError = putbmhd(iff, &ilbm.Bmhd);
  375.      if(IFFError) pm_error("Error writing BMHD chunk.\n");
  376.   
  377.      if(GfxEnable) InitDisplay(cols, rows, Mode, NumPlanes);
  378.    }
  379.    
  380.    if(Mode == HAM8 || Mode == HAM6)
  381.    { 
  382.      /* fill in the ColorTable in B R G order */
  383.      /* (this is better for HAM encoding)     */       
  384.      for(i=0; i<NumColors; i++)
  385.      {
  386.        ColorTable[i*3]   = PPM_GETB(colormap[i].color);
  387.        ColorTable[i*3+1] = PPM_GETR(colormap[i].color);
  388.        ColorTable[i*3+2] = PPM_GETG(colormap[i].color);
  389.        if(!jpegAGA)
  390.        {
  391.          if(ColorShift == 4)
  392.            SetDisplayColor(i, (PPM_GETR(colormap[i].color) << ColorShift) | 
  393.                                PPM_GETR(colormap[i].color),
  394.                               (PPM_GETG(colormap[i].color) << ColorShift) |
  395.                                PPM_GETG(colormap[i].color),
  396.                               (PPM_GETB(colormap[i].color) << ColorShift) |
  397.                                PPM_GETB(colormap[i].color));
  398.          else
  399.           SetDisplayColor(i, (PPM_GETR(colormap[i].color) << ColorShift),
  400.                              (PPM_GETG(colormap[i].color) << ColorShift),
  401.                              (PPM_GETB(colormap[i].color) << ColorShift));
  402.        }
  403.      }
  404.      free(colormap); /* we don't need the colormap any more */
  405.      colormap = NULL;
  406.  
  407.      if(jpegAGA)
  408.      {
  409.        char *MapDir;
  410.        unsigned short MagicNumber = 0x1203; /* guess what this means! */
  411.        int Reserved=0; 
  412.        unsigned char color;
  413.        MapDir = getenv("MAPDIR");  
  414.  
  415.        ColorMapFile = fopen(ILBMfile, "w");
  416.        
  417.        if(!ColorMapFile && !BaseName)
  418.        {
  419.          if(MapDir)
  420.           if(strlen(MapDir) != 0)
  421.          {
  422.            char *MapDirName;
  423.            int pos,i;
  424.            MapDirName = malloc(strlen(MapDir)+strlen(ILBMfile)+5); /* worst case */
  425.            if(!MapDirName) pm_error("Out of memory.\n");
  426.            strcpy(MapDirName, MapDir);
  427.  
  428.            i = strlen(MapDirName);
  429.            if(MapDirName[i-1] != '/' && MapDirName[i-1] != ':')
  430.            {
  431.              strcat(MapDirName, "/");
  432.              i++;
  433.            }
  434.            i = strlen(ILBMfile);
  435.            while(i > 0 && ILBMfile[i-1] != '/' && ILBMfile[i-1] != ':') i--;
  436.            strcat(MapDirName, &ILBMfile[i]);
  437.            ColorMapFile = fopen(MapDirName, "w");
  438.            if(ColorMapFile) pm_message("Writing mapfile: %s\n", MapDirName);
  439.          }
  440.        }
  441.        else if(!ColorMapFile && BaseName && MapDir)
  442.          if(strlen(MapDir) != 0)
  443.        {
  444.          char *NewName;
  445.          int i;
  446.          NewName = malloc(strlen(MapDir)+strlen(BaseName)+strlen(ILBMfile)); /* worst case */
  447.          if(!NewName) pm_error("Out of memory.\n");
  448.          strcpy(NewName, MapDir);
  449.          i=strlen(NewName);
  450.          if(NewName[i-1] != '/' && NewName[i-1] != ':')
  451.          {
  452.            strcat(NewName, "/");
  453.            i++;
  454.          }
  455.          strcat(NewName, BaseName);
  456.          i=strlen(ILBMfile);
  457.          while(i > 0 && ILBMfile[i-1] != '/' && ILBMfile[i-1] != ':') i--;
  458.          if(strlen(ILBMfile) > i+3)
  459.          {
  460.            strcat(NewName, &ILBMfile[i+3]);
  461.            i = strlen(NewName) - 4;
  462.            if(i < 1) pm_error("Wrong mapfile name.\n");
  463.            while(i > 0 && NewName[i-1] != '.') i--;
  464.            if(NewName[i-1] == '.')
  465.            {
  466.              strcpy(&NewName[i], "map");
  467.              printf("%s\n", NewName);
  468.              ColorMapFile = fopen(NewName, "w");
  469.            }
  470.          }
  471.          free(NewName);
  472.        }
  473.          
  474.  
  475.        if(!ColorMapFile) pm_error("Could not open color map file for jpegAGA.\n");
  476.  
  477.        if(fwrite(&MagicNumber, 2, 1, ColorMapFile) != 1) pm_error("Write error.\n");
  478.        if(fwrite(&Reserved,    4, 1, ColorMapFile) != 1) pm_error("Write error.\n");     
  479.        if(fwrite(ColorTable,  64*3, 1, ColorMapFile) != 1) pm_error("Write error.\n");
  480.        pm_message("Colormap file for jpegAGA/PhotoCDAGA created.\n");
  481.        ppmCleanUp();
  482.        return 0;
  483.      }
  484.  
  485.      memset(ColorCache, 0, 262145); /* clear the color cache */          
  486.  
  487.      do
  488.      {
  489.        int y;
  490.        rowcnt=0;
  491.        
  492.        /* if we don't need an additional color the color cache */
  493.        /* will remain valid and should not be cleared          */
  494.  
  495.        memset(ColorCache, 0, 262145); /* clear the color cache */
  496.    
  497.  
  498.        if(!readall)
  499.        {
  500.          rewind(fppm);
  501.          ppm_readppminit(fppm, &cols, &rows, &maxval, &ppmformat);
  502.        }
  503.  
  504.        /* if we have all colors we can write the CMAP chunk */
  505.        if(NumColors == ColorRegMax+1)
  506.        {
  507.          IFFError = PushChunk(iff, 0, ID_CMAP, (ColorRegMax+1)*3);
  508.          if(IFFError) pm_error("Error writing CMAP header.\n");
  509.  
  510.          for( i = 0; i <= ColorRegMax; i++) 
  511.          {
  512.            ColorRegister cmapReg;
  513.            if(ColorShift == 4) /* HAM6 */
  514.            {
  515.              cmapReg.red   = (ColorTable[i*3+1] << ColorShift)
  516.                              | ColorTable[i*3+1];   /* red */
  517.              cmapReg.green = (ColorTable[i*3+2] << ColorShift)
  518.                              | ColorTable[i*3+2];   /* green */
  519.              cmapReg.blue  = (ColorTable[i*3]   << ColorShift)
  520.                              | ColorTable[i*3];   /* blue */
  521.            }
  522.            else /* HAM8 */
  523.            {
  524.              cmapReg.red   = ColorTable[i*3+1] << ColorShift;   /* red */
  525.              cmapReg.green = ColorTable[i*3+2] << ColorShift;   /* green */
  526.              cmapReg.blue  = ColorTable[i*3]   << ColorShift;   /* blue */ 
  527.            }
  528.            IFFError = WriteChunkBytes(iff, (UBYTE *)&cmapReg, 3);
  529.            if(IFFError!=3) pm_error("Error writing CMAP chunk.\n");
  530.          }
  531.          IFFError = PopChunk(iff); /* close CMAP */
  532.          if(IFFError) pm_error("Error closing CMAP.\n");
  533.  
  534.          /* write the CAMG chunk */
  535.          if(SMR)
  536.          {
  537.            ilbm.camg = SMR_DisplayID;
  538.          }
  539.          else
  540.          {
  541.            if(VGAenable)
  542.            {
  543.              if(cols > 370 || rows > 260)
  544.              {
  545.                ilbm.camg = VGAPRODUCTHAM_KEY;
  546.              }
  547.              else
  548.              {
  549.                ilbm.camg = VGALORESHAMDBL_KEY;
  550.              }
  551.            }
  552.            else
  553.            {
  554.              ilbm.camg = HAM;
  555.              if(cols > 370) ilbm.camg = ilbm.camg | HIRES;
  556.              if(rows > 280) ilbm.camg = ilbm.camg | LACE;
  557.            }
  558.          }
  559.          IFFError = putcamg(iff, &ilbm.camg);
  560.          if(IFFError) pm_error("Error writing CAMG chunk.\n");
  561.  
  562.          /* start with the BODY chunk */
  563.          IFFError = PushChunk(iff, 0, ID_BODY, IFFSIZE_UNKNOWN);
  564.          if(IFFError) pm_error("Error writing BODY header.\n");
  565.        }
  566.  
  567.        /* set a dummy value for AbsMaxError                          */
  568.        /* it will contain the maximum error for the complete picture */ 
  569.        AbsMaxError=0;
  570.   
  571.        for(y=0; y<rows; y++)
  572.        {
  573.          pixel *nextrow;          
  574.  
  575.          MaxError = 0;         
  576.            
  577.          nextrow = next_pixrow(fppm, y, ColorShift);
  578.           
  579.          if(AbortCheck()) pm_error("^C\n");
  580.  
  581.          EncodeHAM(nextrow, hamarray, ColorTable, NumColors*3, (short)cols);
  582.  
  583.          
  584.          /* remember the color of the pixel with the maximum error */
  585.          /* even if MaxError == 0 we will get a valid entry in the */
  586.          /* colormap but it will not be used by the picture        */           
  587.          if(MaxError > AbsMaxError)
  588.          {
  589.            MaxErrorXPos = MaxErrorPos;
  590.            MaxErrorYPos = y;
  591.            AbsMaxError = MaxError;
  592.  
  593.            /* use the color of the pixel with the maximum error as */
  594.            /* a ColorTable entry                                   */
  595.            /* we will have to recompute the picture if we want to  */
  596.            /* use the additional color                             */
  597.            if(NumColors <= ColorRegMax)
  598.            {
  599.              ColorTable[NumColors*3]   = PPM_GETB(pixrow[MaxErrorXPos]);
  600.              ColorTable[NumColors*3+1] = PPM_GETR(pixrow[MaxErrorXPos]);
  601.              ColorTable[NumColors*3+2] = PPM_GETG(pixrow[MaxErrorXPos]);
  602.            }        
  603.          }
  604.  
  605.          /* if all colors are set we can write our row to the BODY chunk */
  606.          if(NumColors == ColorRegMax+1) 
  607.          {
  608.            encode_row(hamarray, cols, NumPlanes);
  609.          }
  610.          DisplayRow(hamarray, cols, y);
  611.        }
  612.  
  613.        /* this is only for debugging purposes */
  614.        if(NumColors <= ColorRegMax)
  615.        {
  616.          #ifdef DEBUG
  617.          pm_message("Max Error: %hd ", AbsMaxError);
  618.          #endif
  619.          if(AbsMaxError == 0)
  620.          {
  621.            printf("\n");
  622.          }
  623.          else
  624.          {
  625.            #ifdef DEBUG
  626.            pm_message("Color %hd, XPos: %hd, YPos: %hd\n", NumColors, MaxErrorXPos, MaxErrorYPos);
  627.            #endif
  628.          }
  629.        }
  630.        SetDisplayColor(NumColors, ColorTable[NumColors*3+1] << ColorShift,
  631.                                   ColorTable[NumColors*3+2] << ColorShift,
  632.                                   ColorTable[NumColors*3]   << ColorShift);
  633.        NumColors = NumColors + 1; 
  634.     
  635.      /* finish if we have set all colors */
  636.      } while(NumColors <= ColorRegMax+1);
  637.  
  638.  
  639.      #ifdef DEBUG
  640.      pm_message("Max Error: %hd, XOffset: %hd YOffset: %hd\n",
  641.                AbsMaxError, MaxErrorXPos, MaxErrorYPos);
  642.  
  643.      pm_message("Colortable: ");
  644.      for(i=0; i<=ColorRegMax; i++)
  645.      {
  646.        pm_message("%hd,%hd,%hd ",ColorTable[i*3],
  647.                    ColorTable[i*3+1],ColorTable[i*3+2]);
  648.      }
  649.      pm_message("\n");
  650.      #endif
  651.  
  652.      /* close the BODY chunk */
  653.      IFFError = PopChunk(iff); 
  654.      if(IFFError) pm_message("Error closing the BODY chunk.\n");
  655.    }
  656.    
  657.  
  658.    else if(Mode == COLORMAP)
  659.    { 
  660.      /* if floyd is nonzero we will use Floyd-Steinberg dithering */
  661.      int row, fs_direction;
  662.      register int col, limitcol, ind;
  663.      register pixel *pP;
  664.      register long sg, sr, sb, err;
  665.      long *temperr;
  666.  
  667.      /*
  668.      ** map the colors in the image to their closest match in the
  669.      ** new colormap, and write 'em out.
  670.      */
  671.        
  672.      pm_message( "Mapping image to new colors...\n" );
  673.  
  674.      /* write the CMAP chunk */
  675.      IFFError = PushChunk(iff, 0, ID_CMAP, NumColors*3);
  676.      if(IFFError) pm_error("Error writing CMAP header.\n");
  677.      for( i = 0; i < NumColors; i++) 
  678.      {
  679.        ColorRegister cmapReg;
  680.        cmapReg.red   = PPM_GETR( colormap[i].color );   /* red   */
  681.        cmapReg.green = PPM_GETG( colormap[i].color );   /* green */
  682.        cmapReg.blue  = PPM_GETB( colormap[i].color );   /* blue  */
  683.        SetDisplayColor(i, cmapReg.red, cmapReg.green, cmapReg.blue);
  684.        IFFError = WriteChunkBytes(iff, (UBYTE *)&cmapReg, 3);
  685.        if(IFFError!=3) pm_error("Error writing CMAP chunk.\n");
  686.      }
  687.      IFFError = PopChunk(iff); /* close CMAP */
  688.      if(IFFError) pm_error("Error closing CMAP.\n");
  689.  
  690.      /* write the CAMG chunk */
  691.      if(SMR)
  692.      {
  693.        ilbm.camg = SMR_DisplayID;
  694.      }
  695.      else
  696.      {
  697.        ilbm.camg = 0;
  698.        if(VGAenable)
  699.        {
  700.          if(cols > 370 || rows > 260)
  701.            ilbm.camg = VGAPRODUCT_KEY;
  702.          else
  703.            ilbm.camg = VGALORESDBL_KEY;
  704.        }
  705.        else
  706.        {
  707.          if(cols > 370) ilbm.camg = ilbm.camg | HIRES;
  708.          if(rows > 280) ilbm.camg = ilbm.camg | LACE;
  709.        }
  710.      }
  711.      IFFError = putcamg(iff, &ilbm.camg);
  712.      if(IFFError) pm_error("Error writing CAMG chunk.\n");
  713.  
  714.      /* start with the BODY chunk */
  715.      IFFError = PushChunk(iff, 0, ID_BODY, IFFSIZE_UNKNOWN);
  716.      if(IFFError) pm_error("Error writing BODY header.\n");
  717.  
  718.      rowcnt=0;
  719.      if(!readall)
  720.      {
  721.        rewind(fppm);
  722.        ppm_readppminit(fppm, &cols, &rows, &maxval, &ppmformat);       
  723.      }
  724.  
  725.      if ( floyd )
  726.      {
  727.        fs_direction = 1;
  728.      }
  729.      for ( row = 0; row < rows; ++row )
  730.      {
  731.        /* PLProgress(row, rows); */
  732.        if(AbortCheck()) pm_error("^C\n");
  733.        if ( floyd )
  734.          for ( col = 0; col < cols + 2; ++col )
  735.            nextrerr[col] = nextgerr[col] = nextberr[col] = 0;
  736.        if ( ( ! floyd ) || fs_direction )
  737.        {
  738.          col = 0;
  739.          limitcol = cols;
  740.          /* pP = pixels[row]; */
  741.          pP = next_pixrow(fppm, row, ColorShift);
  742.        }
  743.        else
  744.        {
  745.          col = cols - 1;
  746.          limitcol = -1;
  747.          /* pP = &(pixels[row][col]); */
  748.          pP = &(next_pixrow(fppm, row, ColorShift)[col]);
  749.        }
  750.        do
  751.        {
  752.          if ( floyd )
  753.          {
  754.            /* Use Floyd-Steinberg errors to adjust actual color. */
  755.            sr = PPM_GETR(*pP) + thisrerr[col + 1] / FS_SCALE;
  756.            sg = PPM_GETG(*pP) + thisgerr[col + 1] / FS_SCALE;
  757.            sb = PPM_GETB(*pP) + thisberr[col + 1] / FS_SCALE;
  758.            if ( sr < 0 ) sr = 0;
  759.            else if ( sr > maxval ) sr = maxval;
  760.            if ( sg < 0 ) sg = 0;
  761.            else if ( sg > maxval ) sg = maxval;
  762.            if ( sb < 0 ) sb = 0;
  763.            else if ( sb > maxval ) sb = maxval;
  764.            PPM_ASSIGN( *pP, sr, sg, sb );
  765.          }
  766.  
  767.          /* use the assembler subroutine for the colormap search */
  768.          /* this will consume most of the CPU time               */                     
  769.          ind = MapColorASM(colormap, PPM_GETR(*pP), PPM_GETG(*pP), PPM_GETB(*pP),
  770.                            NumColors);
  771.            
  772.          /* compare the results of the ASM versus the C routine */
  773.          /* if they differ the ASM routine has a bug...         */
  774.          /* (we don't need them because they are the same now)  */
  775.          #ifdef DEBUG_ASM
  776.          if(ind != MapColor(colormap, PPM_GETR(*pP), PPM_GETG(*pP), PPM_GETB(*pP),
  777.                             NumColors))
  778.            pm_message("Diff: row %d col %d  r %d g %d b %d\n", row,col,
  779.                        (int)PPM_GETR(*pP), (int)PPM_GETG(*pP), (int)PPM_GETB(*pP));
  780.          #endif
  781.  
  782.          if ( floyd )
  783.          {
  784.            /* Propagate Floyd-Steinberg error terms. */
  785.            if ( fs_direction )
  786.            {
  787.              err = ( sr - (long) PPM_GETR( colormap[ind].color ) ) * FS_SCALE;
  788.              thisrerr[col + 2] += ( err * 7 ) / 16;
  789.              nextrerr[col    ] += ( err * 3 ) / 16;
  790.              nextrerr[col + 1] += ( err * 5 ) / 16;
  791.              nextrerr[col + 2] += ( err     ) / 16;
  792.              err = ( sg - (long) PPM_GETG( colormap[ind].color ) ) * FS_SCALE;
  793.              thisgerr[col + 2] += ( err * 7 ) / 16;
  794.              nextgerr[col    ] += ( err * 3 ) / 16;
  795.              nextgerr[col + 1] += ( err * 5 ) / 16;
  796.              nextgerr[col + 2] += ( err     ) / 16;
  797.              err = ( sb - (long) PPM_GETB( colormap[ind].color ) ) * FS_SCALE;
  798.              thisberr[col + 2] += ( err * 7 ) / 16;
  799.              nextberr[col    ] += ( err * 3 ) / 16;
  800.              nextberr[col + 1] += ( err * 5 ) / 16;
  801.              nextberr[col + 2] += ( err     ) / 16;
  802.            }
  803.            else
  804.            {
  805.              err = ( sr - (long) PPM_GETR( colormap[ind].color ) ) * FS_SCALE;
  806.              thisrerr[col    ] += ( err * 7 ) / 16;
  807.              nextrerr[col + 2] += ( err * 3 ) / 16;
  808.              nextrerr[col + 1] += ( err * 5 ) / 16;
  809.              nextrerr[col    ] += ( err     ) / 16;
  810.              err = ( sg - (long) PPM_GETG( colormap[ind].color ) ) * FS_SCALE;
  811.              thisgerr[col    ] += ( err * 7 ) / 16;
  812.              nextgerr[col + 2] += ( err * 3 ) / 16;
  813.              nextgerr[col + 1] += ( err * 5 ) / 16;
  814.              nextgerr[col    ] += ( err     ) / 16;
  815.              err = ( sb - (long) PPM_GETB( colormap[ind].color ) ) * FS_SCALE;
  816.              thisberr[col    ] += ( err * 7 ) / 16;
  817.              nextberr[col + 2] += ( err * 3 ) / 16;
  818.              nextberr[col + 1] += ( err * 5 ) / 16;
  819.              nextberr[col    ] += ( err     ) / 16;
  820.            }
  821.          }
  822.  
  823.          /* *pP = colormap[ind].color; */
  824.          hamarray[col] = (unsigned char)ind;
  825.  
  826.          if ( ( ! floyd ) || fs_direction )
  827.          {
  828.            ++col;
  829.            ++pP;
  830.          }
  831.          else
  832.          {
  833.            --col;
  834.            --pP;
  835.          }
  836.        }
  837.        while ( col != limitcol );
  838.  
  839.        if ( floyd )
  840.        {
  841.          temperr = thisrerr;
  842.          thisrerr = nextrerr;
  843.          nextrerr = temperr;
  844.          temperr = thisgerr;
  845.          thisgerr = nextgerr;
  846.          nextgerr = temperr;
  847.          temperr = thisberr;
  848.          thisberr = nextberr;
  849.          nextberr = temperr;
  850.          fs_direction = ! fs_direction;
  851.        }
  852.  
  853.        /* ppm_writeppmrow( stdout, pixels[row], cols, maxval, 0 ); */
  854.        /* write one row to the BODY chunk */
  855.        encode_row(hamarray, cols, NumPlanes);
  856.        DisplayRow(hamarray, cols, row);
  857.      }
  858.      IFFError = PopChunk(iff); /* close the BODY */
  859.      if(IFFError) pm_error("Error closing the BODY chunk.\n");
  860.    }       
  861.  }
  862.  
  863.  closeifile((struct ParseInfo *)&ilbm);
  864.  ppmCleanUp();
  865.  return 0;
  866. }
  867.  
  868.  
  869. /* free all resources used by this module */
  870. void ppmCleanUp(void)
  871. {
  872.  CloseDisplay();
  873.  if(colormap) free(colormap);
  874.  if(pgmrow) pgm_freerow(pgmrow); 
  875.  if(coded_rowbuf) free(coded_rowbuf);
  876.  if(CompressBuffer) free(CompressBuffer);
  877.  if(ColorCache) free(ColorCache);
  878.  if(chv) free(chv);
  879.  if(hamarray) free(hamarray);
  880.  if(pixels)
  881.  {
  882.    ppm_freearray(pixels, rows);
  883.  } 
  884.  else
  885.  {
  886.    if(pixrow) pbm_freerow(pixrow);
  887.  }
  888.  if(fppm) fclose(fppm);
  889.  
  890.  if(jpegAGA)
  891.  {
  892.    if(ColorMapFile)
  893.    {
  894.      fclose(ColorMapFile);
  895.      ColorMapFile = NULL;
  896.    }
  897.  }
  898.  else
  899.  {
  900.    if(ilbm.ParseInfo.opened)
  901.    {
  902.      closeifile((struct ParseInfo *)&ilbm);
  903.      remove(ILBMfile);
  904.    }
  905.    if(ilbm.ParseInfo.iff) FreeIFF(ilbm.ParseInfo.iff);
  906.  }
  907. }
  908.  
  909.  
  910.  
  911. /* convert one row from chunky to planar, compress it, */
  912. /* and write it to the BODY chunk                      */
  913.  
  914. /* encode algorithm by Johan Widen (jw@jwdata.se) */
  915. /* modified by Günther Röhrich */
  916.  
  917. const unsigned char bit_mask[] = {1, 2, 4, 8, 16, 32, 64, 128};
  918.  
  919. static void
  920. encode_row(UBYTE *row, int cols, int nPlanes)
  921. {
  922.  register int plane, col;
  923.  int bytes;
  924.  LONG packedRowBytes;
  925.  BYTE *source;
  926.  BYTE *destination;
  927.  
  928.  bytes = RowBytes(cols);
  929.  
  930.  /* Encode and write raw bytes in plane-interleaved form. */
  931.  for( plane = 0; plane < nPlanes; plane++ ) 
  932.  {
  933.    int mask, cbit, wr;
  934.    unsigned char *cp;
  935.    UBYTE *rp;
  936.  
  937.    mask = 1 << plane;
  938.    cbit = -1;
  939.    cp = coded_rowbuf-1;
  940.    rp = row;
  941.    for( col = 0; col < cols; col++, cbit--, rp++ ) 
  942.    {
  943.      if( cbit < 0 ) 
  944.      {
  945.        cbit = 7;
  946.        *++cp = 0;
  947.      }
  948.      if( *rp & mask )
  949.        *cp |= bit_mask[cbit];
  950.    }
  951.    /* wr = fwrite(coded_rowbuf, 1, bytes, stdout); */
  952.  
  953.    /* compress the row */
  954.    source = coded_rowbuf;
  955.    destination = CompressBuffer;
  956.    packedRowBytes = packrow(&source, &destination, bytes);
  957.  
  958.    /* write the compressed row to the BODY chunk */  
  959.    IFFError = WriteChunkBytes(iff, CompressBuffer, packedRowBytes); 
  960.    if(IFFError!=packedRowBytes) pm_error("Error writing BODY chunk.\n");
  961.  }
  962. }
  963.  
  964.  
  965. #ifdef DEBUG_ASM
  966. /* this is the C version of the colormap search routine */
  967. /* (it is now replaced by the ASM version)              */
  968.  
  969. /* search colormap for closest match. */
  970. int MapColor(colorhist_vector colormap, pixval r, pixval g, pixval b, 
  971.              int newcolors)
  972.  int ind;
  973.  register int i, r1, g1, b1, r2, g2, b2;
  974.  register long dist, newdist;
  975.  r1 = r;
  976.  g1 = g;
  977.  b1 = b;
  978.  dist = 2000000000;
  979.  for ( i = 0; i < newcolors; ++i )
  980.  {
  981.    r2 = PPM_GETR( colormap[i].color );
  982.    g2 = PPM_GETG( colormap[i].color );
  983.    b2 = PPM_GETB( colormap[i].color );
  984.    newdist = ( r1 - r2 ) * ( r1 - r2 ) +
  985.              ( g1 - g2 ) * ( g1 - g2 ) +
  986.              ( b1 - b2 ) * ( b1 - b2 );
  987.    if ( newdist < dist )
  988.    {
  989.      ind = i;
  990.      dist = newdist;
  991.    }
  992.  }
  993.  return ind;
  994. }
  995. #endif
  996.  
  997.  
  998.